//
//      Copyright 2011 Hengda Xiao 224080
//
//      Millionare
//
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//
//      04.05.2011


#include "gamesystem.h"



using std::cout;
using std::cin;
using std::vector;
using std::endl;
using std::string;

const int ELEVEN = 11;
const int TWELEVE = 12;
const int THRITEEN = 13;
const int TWOFIVESIX = 256;


//The import function will be done in the construction part

GameSystem::GameSystem(char **argv):questRdy(false),random_quest(TWELEVE),quest_vec(THRITEEN),
                                    questionTotalNum(0),choice(0),
                                    Quit(false)

{
    ImportQuestion(argv);
    //DoChoice_Quest();
}




//Delte all pointers

GameSystem::~GameSystem()
{
    for(int i = 0; i < THRITEEN; i++){
        for(unsigned int j = 0; j < quest_vec[i].size();j++){
            delete quest_vec[i][j];
            quest_vec[i][j] = NULL;
        }
    }
}


//Open the text file and check if there are enough questions to
//generate random question list

void GameSystem::ImportQuestion(char **argv)
{
    inFile.open(argv[1]);
    ClassifyQuest();
    inFile.close();
    int totalNumber = CheckQuestionTotal();
    CheckEnoughQuest();
    if(questRdy){
        cout << "The game questions are prepared successful!" << endl;
        cout << "The total number of question is: " << totalNumber << endl;
    }
}



//According the different level, the system will transfer the level to the
//fillquest function to finish the filling the question part.

void GameSystem::ClassifyQuest()
{
    while(!inFile.eof()){
        getline(inFile,tempStr);
        int level = 0;
        std::stringstream sstream_class(tempStr);
        sstream_class >> level;
        switch(level)
        {
        case 1:
            FillQuest(level);
            break;
        case 2:
            FillQuest(level);
            break;
        case 3:
            FillQuest(level);
            break;
        case 4:
            FillQuest(level);
            break;
        case 5:
            FillQuest(level);
            break;
        case 6:
            FillQuest(level);
            break;
        case 7:
            FillQuest(level);
            break;
        case 8:
            FillQuest(level);
            break;
        case 9:
            FillQuest(level);
            break;
        case 10:
            FillQuest(level);
            break;
        case ELEVEN:
            FillQuest(level);
            break;
        case TWELEVE:
            FillQuest(level);
            break;
        default:
            break;
        }
    }
}




//Depend on the received level, it will then set each quesion attributes
//from the following lines. At last, put the question into the vector.

void GameSystem::FillQuest(int level)
{
    Question *quest = new Question;
    quest->setLevel(level);
    for(int i = 1; i <= 7; i++){
        getline(inFile,tempStr);
        int number_quest = 0;
        std::stringstream sstream_fill(tempStr);
        sstream_fill >> number_quest;
        switch(i){
        case 1:
            quest->setQuestNumber(number_quest);
            break;
        case 2:
            quest->setDes(tempStr);
            break;
        case 3:
            quest->setChoiceA(tempStr);
            break;
        case 4:
            quest->setChoiceB(tempStr);
            break;
        case 5:
            quest->setChoiceC(tempStr);
            break;
        case 6:
            quest->setChoiceD(tempStr);
            break;
        case 7:
            quest->setCorrectAns(tempStr);
            break;
        default:
            cout << "Fill question error!" << endl;
            break;
        }
    }
    quest_vec[level].push_back(quest);
}




//Show the menu of quesion part

void GameSystem::Menu_Quest()
{
    cout << "\nSelect menu item:" << endl;
    cout << "\n[1] Add a new question" << endl;
    cout << "[2] Edit a new question" << endl;
    cout << "[3] Remove a question" << endl;
    cout << "[4] Print all questions" << endl;
    cout << "[5] Print a question by number" << endl;
    cout << "[6] Print questions of a given difficulty level" << endl;
    cout << "[7] Save questions to a file" << endl;
    cout << "[8] Generate a question set" << endl;
    cout << "[9] Print the generated question set" << endl;
    cout << "[10]Back to main menu " << endl;
    cout << "\nYour choice:";

    string strChoice;
    cin >> strChoice;
    while(!StringCheck(strChoice))
    {
        cout << "\nMust enter the number!" << endl;
        cout << "Please enter your choice again!" << endl;
        cout << "Your choice:";
        cin >> strChoice;
    }
    std::stringstream sstream_choice(strChoice);
    sstream_choice >> choice;
}



//Check the total question number


int GameSystem::CheckQuestionTotal()
{
    for(int i = 0; i < THRITEEN; i++){
        for(unsigned int j = 0; j < quest_vec[i].size();j++){
            questionTotalNum++;
        }
    }
    return questionTotalNum;
}




//According input, to run different function

void GameSystem::DoChoice_Quest()
{
   Quit = false;
    while(!Quit){
        Menu_Quest();
        switch(choice)
        {
        case 1:
            AddQuest();
            break;
        case 2:
            EditQuest();
            break;
        case 3:
            RemoveQuest();
            break;
        case 4:
            PrintAllQuest();
            break;
        case 5:
            PrintByNumber();
            break;
        case 6:
            PrintByLevel();
            break;
        case 7:
            SaveQuest();
            break;
        case 8:
            GenerateQuest();
            break;
        case 9:
            PrintGerQuest();
            break;
        case 10:
            Quit = true;
            break;
        default:
            cout << "Error! " << endl;
            break;
        }
    }
}





//Add quest function, the system will ask user to input
//attributes of the question, and finnally add the question
//to the end of 2d vector in different level

void GameSystem::AddQuest()
{
    string addStr;
    int level;
    cin.ignore();
    cout << "Level of the question: ";
    getline(cin,addStr);
    while(!StringCheck(addStr))
    {
        cout << "\nMust enter the number!" << endl;
        cout << "Please enter your choice again!" << endl;
        cout << "\nLevel of the question: ";
        getline(cin,addStr);
    }
    std::stringstream sstream_level(addStr);
    sstream_level >> level;
    Question *quest = new Question;
    quest->setLevel(level);
    cout << "\nDescription of the question: ";
    getline(cin,addStr);
    quest->setDes(addStr);
    cout << "\nChoice A of the question: ";
    getline(cin,addStr);
    quest->setChoiceA(addStr);
    cout << "\nChoice B of the question: ";
    getline(cin,addStr);
    quest->setChoiceA(addStr);
    cout << "\nChoice C of the question: ";
    getline(cin,addStr);
    quest->setChoiceC(addStr);
    cout << "\nChoice D of the question: ";
    getline(cin,addStr);
    quest->setChoiceD(addStr);
    cout << "\nCorrect answer of the question: ";
    getline(cin,addStr);
    quest->setCorrectAns(addStr);

    questionTotalNum++;
    quest->setQuestNumber(questionTotalNum);

    quest_vec[level].push_back(quest);
}




//denpend on the question number, the system will go through
//the whole 2d vector and find the corresponding question
//then edit different attributes of the question

void GameSystem::EditQuest()
{
    int number;
    string editStr;
    cin.ignore();
    cout << "Seleec question number [1-" << questionTotalNum <<"]: ";
    getline(cin,editStr);
    while(!StringCheck(editStr))
    {
      cout << "\nMust enter the number!" << endl;
      cout << "Please enter your choice again!" << endl;
      cout << "Seleec question number [1-" << questionTotalNum <<"]: ";
      getline(cin,editStr);
    }
     std::stringstream sstream_number(editStr);
     sstream_number >> number;
     for(int i = 1; i < THRITEEN; i++){
         for(unsigned int j = 0; j < quest_vec[i].size();j++){
             if(quest_vec[i][j]->getQuestNumber() == number){
                 cout << "Editing question #" << number << endl;
                 cout << "------------------------------------------------------------------";
                 quest_vec[i][j]->printDescription();
                 cout << "[A]";
                 quest_vec[i][j]->printChoiceA();
                 cout << "[B]";
                 quest_vec[i][j]->printChoiceB();
                 cout << "[C]";
                 quest_vec[i][j]->printChoiceC();
                 cout << "[D]";
                 quest_vec[i][j]->printChoiceD();
                 cout << "------------------------------------------------------------------" << endl;
                 cout << "\nDescription of the question: ";
                 getline(cin,editStr);
                 quest_vec[i][j]->setDes(editStr);
                 cout << "\nChoice A of the question: ";
                 getline(cin,editStr);
                 quest_vec[i][j]->setChoiceA(editStr);
                 cout << "\nChoice B of the question: ";
                 getline(cin,editStr);
                 quest_vec[i][j]->setChoiceA(editStr);
                 cout << "\nChoice C of the question: ";
                 getline(cin,editStr);
                 quest_vec[i][j]->setChoiceC(editStr);
                 cout << "\nChoice D of the question: ";
                 getline(cin,editStr);
                 quest_vec[i][j]->setChoiceD(editStr);
                 cout << "\nCorrect answer of the question: ";
                 getline(cin,editStr);
                 quest_vec[i][j]->setCorrectAns(editStr);
             }
         }
     }
 }




//Also depend on the question number for finding the corrsponding
//question from 2d vector and delte the question from vector


void GameSystem::RemoveQuest()
{
    int number;
    string removeStr;
    cin.ignore();
    cout << "Seleec question number [1-" << questionTotalNum <<"]: ";
    getline(cin,removeStr);
    while(!StringCheck(removeStr))
    {
      cout << "\nMust enter the number!" << endl;
      cout << "Please enter your choice again!" << endl;
      cout << "Seleec question number [1-" << questionTotalNum <<"]: ";
      getline(cin,removeStr);
    }
     std::stringstream sstream_number(removeStr);
     sstream_number >> number;
     for(int i = 1; i < THRITEEN; i++){
         for(unsigned int j = 0; j < quest_vec[i].size();j++){
             if(quest_vec[i][j]->getQuestNumber() == number){
                 quest_vec[i].erase(quest_vec[i].begin() + j);
                 questionTotalNum--;
             }
         }
     }
     for(int i = 1; i < THRITEEN; i++){
         for(unsigned int j = 0; j < quest_vec[i].size();j++){
             if(quest_vec[i][j]->getQuestNumber() > number){
                 int preNumber = quest_vec[i][j]->getQuestNumber();
                 quest_vec[i][j]->setQuestNumber(preNumber - 1);
             }
         }
     }
}




//Go through all the 2d vector and display all question by using two
//for loops


void GameSystem::PrintAllQuest()
{
    for(int i = 1; i < THRITEEN; i++){
        for(unsigned int j = 0; j < quest_vec[i].size();j++){
            cout << "------------------------------------------------------------------";
            quest_vec[i][j]->printDescription();
            cout << "[A]";
            quest_vec[i][j]->printChoiceA();
            cout << "[B]";
            quest_vec[i][j]->printChoiceB();
            cout << "[C]";
            quest_vec[i][j]->printChoiceC();
            cout << "[D]";
            quest_vec[i][j]->printChoiceD();
            cout << "------------------------------------------------------------------" << endl;
        }
    }
}





//select the question from vector by using question number

void GameSystem::PrintByNumber()
{
    int number;
    string numberStr;
    cin.ignore();
    cout << "Seleec question number [1-" << questionTotalNum <<"]: ";
    getline(cin,numberStr);
    while(!StringCheck(numberStr))
    {
      cout << "\nMust enter the number!" << endl;
      cout << "Please enter your choice again!" << endl;
      cout << "Seleec question number [1-" << questionTotalNum <<"]: ";
      getline(cin,numberStr);
    }
     std::stringstream sstream_number(numberStr);
     sstream_number >> number;
     for(int i = 1; i < THRITEEN; i++){
         for(unsigned int j = 0; j < quest_vec[i].size();j++){
             if(quest_vec[i][j]->getQuestNumber() == number){
                 cout << "------------------------------------------------------------------";
                 quest_vec[i][j]->printDescription();
                 cout << "[A]";
                 quest_vec[i][j]->printChoiceA();
                 cout << "[B]";
                 quest_vec[i][j]->printChoiceB();
                 cout << "[C]";
                 quest_vec[i][j]->printChoiceC();
                 cout << "[D]";
                 quest_vec[i][j]->printChoiceD();
                 cout << "------------------------------------------------------------------" << endl;
             }
         }
     }
 }






//Choose a specific level and show all the questions included in the level

void GameSystem::PrintByLevel()
{
    string levelStr;
    int level;
    cin.ignore();
    cout << "Seleec question number [1-12]: ";
    getline(cin,levelStr);
    while(!StringCheck(levelStr))
    {
        cout << "\nMust enter the number!" << endl;
        cout << "Please enter your choice again!" << endl;
        cout << "Seleec question number [1-12]: ";
        getline(cin,levelStr);
    }
    std::stringstream sstream_level(levelStr);
    sstream_level >> level;
    for(unsigned int i = 0; i < quest_vec[level].size();i++){
        cout << "------------------------------------------------------------------";
        quest_vec[level][i]->printDescription();
        cout << "[A]";
        quest_vec[level][i]->printChoiceA();
        cout << "[B]";
        quest_vec[level][i]->printChoiceB();
        cout << "[C]";
        quest_vec[level][i]->printChoiceC();
        cout << "[D]";
        quest_vec[level][i]->printChoiceD();
        cout << "------------------------------------------------------------------" << endl;
    }

}





//Save all the questions to a text file


void GameSystem::SaveQuest()
{
    char filename[TWOFIVESIX];//create a char arrary
    char *p = filename;//give the address to a char pointer
    cout << "Give the file a name:";
    cin >> p;//input the file name
    outFile.open(p);//open the file
    for(int i = 1; i < THRITEEN; i++){
        for(unsigned int j = 0; j < quest_vec[i].size();j++){
            outFile << quest_vec[i][j]->getLevel() << endl;
            outFile << quest_vec[i][j]->getQuestNumber()<< endl;
            outFile << quest_vec[i][j]->getDescription()<< endl;
            outFile << quest_vec[i][j]->getChoiceA()<< endl;
            outFile << quest_vec[i][j]->getChoiceA()<< endl;
            outFile << quest_vec[i][j]->getChoiceA()<< endl;
            outFile << quest_vec[i][j]->getChoiceD()<< endl;
            outFile << quest_vec[i][j]->getCorrectAns()<< endl;
        }
    }

}






//Gernate a random question list from differetn level


void GameSystem::GenerateQuest()
{
    random_quest.clear();
    int randomNum = 0;
    int upperBound = 0;
    for(int i = 1; i < THRITEEN; i++ ){
        upperBound = static_cast<int>(quest_vec[i].size());
        std::srand(std::time(NULL));
        randomNum = std::rand()%upperBound;
        random_quest.push_back(quest_vec[i][randomNum]);
    }
    cout << "Generate question success!" << endl;
}





//Print out the generate questions


void GameSystem::PrintGerQuest()
{
    for(unsigned int i = 0; i < random_quest.size();i++){
        cout << "------------------------------------------------------------------" << endl;
        cout << "Level: ";
        cout << random_quest[i]->getLevel() << endl;
        cout << "Number: ";
        cout << random_quest[i]->getQuestNumber() << endl;
        random_quest[i]->printDescription();
        cout << "[A]";
        random_quest[i]->printChoiceA();
        cout << "[B]";
        random_quest[i]->printChoiceB();
        cout << "[C]";
        random_quest[i]->printChoiceC();
        cout << "[D]";
        random_quest[i]->printChoiceD();
        cout << "------------------------------------------------------------------" << endl;
    }
}









void GameSystem::Menu_Player()
{
    cout << "[1] Start Game" <<endl;
    cout << "[2] Instructions" << endl;
    cout << "[3] Player Statistics" << endl;

}




//Check if the user input the correct command

bool GameSystem::StringCheck(string str)
{
    for(unsigned int i = 0; i <str.size();i++)
    {
        char c = char(str[i]);
        bool f = std::isdigit(c);
        if(!f)
        {
            return false;
        }
    }
    return true;
}



//Check if there is enough question



void GameSystem::CheckEnoughQuest()
{
    unsigned int levelSize = 0;
    for(int i = 1; i < THRITEEN; i ++){
        levelSize = quest_vec[i].size();
        if(levelSize == 0){
            cout << "The question part is not ready!" << endl;
            questRdy = false;
            break;
        }
    questRdy = true;
    }

}
